package pages;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import database.DBException;
import database.DBUtils;

import templates.Template;

/**
 * Servlet implementation class AddInstrument
 */
public class AddInstrument extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private static final String pageTitle = "New Instrument";
	private static final String templateName = "addInstrument";
	private static final String typesComboTemplateName = "types_combo";
	private static final String typeOptionTemplateName = "type_option";
	private static final String timeSlotTemplateName = "time_slot_combo";
	private static final String successTemplateName = "successInstrumentAdd";

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public AddInstrument() {
		super();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		initRequestAttributes(request);
		try {
			Template template = new Template(templateName);
			template.addChange("error", LMUtils.getRequestAttribute(request,
					"error"));
			template.addChange("newTypeName", LMUtils.getRequestAttribute(
					request, "newTypeName"));
			template.addChange("instrumentName", LMUtils.getRequestAttribute(
					request, "newInstrumentName"));
			template.addChange("newInstrumentDescription", LMUtils
					.getRequestAttribute(request, "newInstrumentDescription"));
			template.addChange("types_combo",
					generateTypesCombo((Integer) request
							.getAttribute("newInstrumentTypeID")));

			// timeSlot combo
			Template timeSlotTemplate = new Template(timeSlotTemplateName);
			template.addChange("timeslots_combo", timeSlotTemplate
					.applyChanges());
			// template = LMUtils.adminMenu(template);

			response.getWriter().print(
					template.createPage(pageTitle, LMUtils
							.getUserLogin(request)));
		} catch (Exception e) {
			ErrorPage.printErrorPage(e.getMessage(), request, response);
		}
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		LMUtils.setRequestAttribute(request, "error", "");

		try {
			int newInstrumentTypeID = Integer.valueOf(LMUtils
					.getRequestParameterValueNotEmpty(request, "type"));
			request.setAttribute("newInstrumentTypeID", newInstrumentTypeID);
			try {
				if (newInstrumentTypeID == 0) {
					String newTypeName = LMUtils
							.getRequestParameterValueNotEmpty(request,
									"newTypeName");
					LMUtils.setRequestAttribute(request, "newTypeName",
							newTypeName);
					newInstrumentTypeID = insertNewType(newTypeName);
					request.setAttribute("newInstrumentTypeID",
							newInstrumentTypeID);
				}
			} catch (MissingParameterException e) {
				LMUtils.setRequestAttribute(request, "error",
						"Please fill in type name");
			} catch (Exception e) {
				LMUtils.setRequestAttribute(request, "error", e.getMessage());
			}
		} catch (NumberFormatException e) {
			LMUtils.setRequestAttribute(request, "error",
					"Please specify instrument type");
		} catch (MissingParameterException e) {
			LMUtils.setRequestAttribute(request, "error",
					"Please specify instrument type");
		}

		try {
			request.setAttribute("timeSlot", Integer.valueOf(LMUtils
					.getRequestParameterValueNotEmpty(request, "timeSlot")));
		} catch (Exception e) {
			LMUtils.setRequestAttribute(request, "error",
					"Please specify time slot");
		}

		try {
			LMUtils.setRequestAttribute(request, "newInstrumentDescription",
					LMUtils.getRequestParameterValue(request,
							"newInstrumentDescription"));
		} catch (Exception e) {
			LMUtils
					.setRequestAttribute(request, "newInstrumentDescription",
							"");
		}

		try {
			LMUtils.setRequestAttribute(request, "newInstrumentName",
					LMUtils.getRequestParameterValueNotEmpty(request,
							"instrumentName"));
		} catch (Exception e) {
			LMUtils.setRequestAttribute(request, "error",
					"Please specify instrument name");
		}

		// adding new instrument
		if (LMUtils.getRequestAttribute(request, "error").isEmpty()) {
			try {
				String newInstrumentName = LMUtils.getRequestAttribute(request,
						"newInstrumentName");
				int newInstrumentTypeID = (Integer) request
						.getAttribute("newInstrumentTypeID");
				int timeSlot = (Integer) request.getAttribute("timeSlot");
				String newInstrumentDescription = LMUtils.getRequestAttribute(
						request, "newInstrumentDescription");
				addNewInstrument(newInstrumentName, newInstrumentTypeID,
						timeSlot, newInstrumentDescription);
			} catch (Exception e) {
				LMUtils.setRequestAttribute(request, "error",
						"Can't create new instrument: " + e.getMessage());
			}
		}

		if (LMUtils.getRequestAttribute(request, "error").isEmpty()) {
			try {
				Template successTemplate = new Template(successTemplateName);

				response.getWriter().print(
						successTemplate.createPage("Success Register", LMUtils
								.getUserLogin(request)));
			} catch (InternalErrorException e) {
				ErrorPage.printErrorPage(e.getMessage(), request, response);
			}
		} else {
			doGet(request, response);
		}

	}

	/**
	 * Fetches all instruments types from DB
	 * 
	 * @return Combo Box containing all the types + one row (make new type)
	 * @throws InternalErrorException
	 * @throws DBException
	 * @throws SQLException
	 */
	private String generateTypesCombo(int selectedTypeID)
			throws InternalErrorException, DBException, SQLException {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String typesTableName = LMUtils.getContextParameterValue(
					getServletContext(), "db.TypesTableName");
			String query = "SELECT `id`, `name` FROM `"
					+ typesTableName
					+ "` WHERE 1 UNION (SELECT 0 as `id` , 'Create new type' as `name`);";

			Template typeComboTemplate = new Template(typesComboTemplateName);
			Template typeOptionTemplate = new Template(typeOptionTemplateName);
			String typeOptionsText = "";

			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			rs = stmt.executeQuery();
			while (rs.next()) {
				Integer typeID = rs.getInt("id");
				typeOptionTemplate.addChange("typeID", typeID.toString());
				typeOptionTemplate.addChange("type_name", rs.getString("name"));
				typeOptionTemplate
						.addChange(
								"selected",
								typeID == selectedTypeID ? "selected=\"selected\""
										: "");
				typeOptionsText += typeOptionTemplate.applyChanges();
			}
			typeComboTemplate.addChange("types_options", typeOptionsText);

			return typeComboTemplate.applyChanges();
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);

		}
	}

	/**
	 * Inserts new instrument type
	 * 
	 * @param typeName
	 * @return newInstrumentTypeID
	 * @throws InternalErrorException
	 * @throws DBException
	 */
	private int insertNewType(String typeName) throws InternalErrorException,
			DBException {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String typesTableName = LMUtils.getContextParameterValue(
					getServletContext(), "db.TypesTableName");
			String query = "INSERT INTO `" + typesTableName + "` (`name`)"
					+ " VALUES (?);";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setString(1, typeName);
			stmt.execute();

			rs = stmt.getGeneratedKeys();
			if (rs != null && rs.next()) {
				return rs.getInt(1);
			} else {
				throw new DBException("Can't create new type.");
			}
		} catch (SQLException e) {
			// throw new DBException("Can't create new type: " + e.getMessage(),
			// e);
			throw new DBException(
					"Such type already exists. Please specify another type name");
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Inserts new instrument
	 * 
	 * @param newInstrumentName
	 * @param newInstrumentTypeID
	 * @param timeSlot
	 * @param newInstrumentDescription
	 * @throws InternalErrorException
	 * @throws DBException
	 */
	private void addNewInstrument(String newInstrumentName,
			int newInstrumentTypeID, int timeSlot,
			String newInstrumentDescription) throws InternalErrorException,
			DBException {
		if (!isTypeExists(newInstrumentTypeID)) {
			throw new DBException("Wrong instrument type");
		}
		Connection conn = null;
		PreparedStatement stmt = null;
		try {
			String instrumentsTableName = LMUtils.getContextParameterValue(
					getServletContext(), "db.InstrumentsTableName");
			String query = "INSERT INTO `"
					+ instrumentsTableName
					+ "` (`Name`, `typeID`, `timeSlot`, `description`, `messageForUsers`, `isActive`)"
					+ " VALUES (?, ?, ?, ?, '', 1);";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setString(1, newInstrumentName);
			stmt.setInt(2, newInstrumentTypeID);
			stmt.setInt(3, timeSlot);
			stmt.setString(4, newInstrumentDescription);
			stmt.execute();
		} catch (SQLException e) {
			throw new DBException("Can't create new type: " + e.getMessage(), e);
		} finally {
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Checks if type with typeID exists in DB
	 * 
	 * @param typeID
	 * @return true if exists, false if not
	 * @throws InternalErrorException
	 * @throws DBException
	 */
	private boolean isTypeExists(int typeID) throws InternalErrorException,
			DBException {
		Connection conn = null;
		PreparedStatement stmt = null;
		ResultSet rs = null;
		try {
			String typesTableName = LMUtils.getContextParameterValue(
					getServletContext(), "db.TypesTableName");
			String query = "SELECT `id` FROM `" + typesTableName
					+ "` WHERE `id` = ? LIMIT 1;";
			conn = DBUtils.getConnection();
			stmt = conn.prepareStatement(query);
			stmt.setInt(1, typeID);
			rs = stmt.executeQuery();
			return rs.next();
		} catch (SQLException e) {
			throw new DBException(e.getMessage());
		} finally {
			DBUtils.close(rs);
			DBUtils.close(stmt);
			DBUtils.close(conn);
		}
	}

	/**
	 * Initializes default values to some request variables
	 * 
	 * @param request
	 */
	private void initRequestAttributes(HttpServletRequest request) {
		if (request.getAttribute("newInstrumentTypeID") == null) {
			request.setAttribute("newInstrumentTypeID", -1);
		}
		if (request.getAttribute("timeSlot") == null) {
			request.setAttribute("timeSlot", -1);
		}
	}
}